package com.bytedance.lucky.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Date;

/**
 * 为了方便获取配置属性，所以工具类使用组件形式
 *
 * @author zouyaowen
 * @date 2021-02-13 01:08
 */
@Component
@Slf4j
public class JwtUtil {

    /**
     * 秘钥,默认:aaaaabbbbbcccccdddddaaaaabbbbbcccccdddddaaaaabbbbbcccccdddddaaaaabbbbbcccccddddd
     * 秘钥必须大于72bit
     */
    @Value("${secret:aaaaabbbbbcccccdddddaaaaabbbbbcccccdddddaaaaabbbbbcccccdddddaaaaabbbbbcccccddddd}")
    private String secret;
    /**
     * 有效期，单位秒,默认2周
     */
    @Value("${expire-time-in-hour:72}")
    private Integer expirationTimeInHour;

    /**
     * token发布者
     */
    @Value("${jwt-issuer:lucky}")
    private String jwtIssuer;

    public String buildToken(UserTokenInfo userTokenInfo) {
        Algorithm algorithm = Algorithm.HMAC256(secret);
        LocalDateTime expireTime = LocalDateTime.now().plusHours(expirationTimeInHour);
        return JWT.create()
                // 发布者
                .withIssuer(jwtIssuer)
                // 生成签名的时间
                .withIssuedAt(new Date())
                // 生成签名的有效期
                .withExpiresAt(DateUtils.asDate(expireTime))
                .withClaim(UserTokenInfo.USER_NAME, userTokenInfo.userName)
                .withClaim(UserTokenInfo.ID, userTokenInfo.id)
                .sign(algorithm);
    }

    public Boolean verifyToken(String token) {
        Algorithm algorithm = Algorithm.HMAC256(secret);
        JWTVerifier verifier = JWT.require(algorithm)
                // 匹配指定的token发布者 lucky
                .withIssuer(jwtIssuer)
                .build();
        try {
            //解码JWT
            verifier.verify(token);
        } catch (TokenExpiredException e) {
            return false;
        } catch (RuntimeException e) {
            log.error("Token解析异常", e);
            return false;
        }
        return true;
    }

    @Data
    public static class UserTokenInfo {
        private static final String USER_NAME = "userName";
        private static final String ID = "id";
        private Long id;
        private String userName;
    }
}
